package com.jpro.module.system.api.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
import com.jpro.framework.common.pojo.CommonResult;
import com.jpro.framework.common.pojo.PageResult;
import com.jpro.framework.common.util.collection.CollectionUtils;
import com.jpro.framework.common.util.object.BeanUtils;
import com.jpro.framework.tenant.core.context.TenantContextHolder;
import com.jpro.module.system.api.user.dto.AdminUserRespDTO;
import com.jpro.module.system.api.user.dto.MemberCreateReqDTO;
import com.jpro.module.system.api.user.dto.MemberUserRespDTO;
import com.jpro.module.system.api.user.dto.UserAvatarDto;
import com.jpro.module.system.api.user.vo.*;
import com.jpro.module.system.config.JproProperties;
import com.jpro.module.system.controller.admin.membergroup.vo.MemberGroupExportReqVO;
import com.jpro.module.system.convert.user.UserConvert;
import com.jpro.module.system.dal.dataobject.dept.DeptDO;
import com.jpro.module.system.dal.dataobject.membergroup.MemberGroupDO;
import com.jpro.module.system.dal.dataobject.user.AdminUserDO;
import com.jpro.module.system.dal.mysql.user.AdminUserMapper;
import com.jpro.module.system.enums.logger.LoginLogTypeEnum;
import com.jpro.module.system.enums.user.EnumMemberGroupType;
import com.jpro.module.system.service.auth.AdminAuthService;
import com.jpro.module.system.service.dept.DeptService;
import com.jpro.module.system.service.membergroup.MemberGroupService;
import com.jpro.module.system.service.permission.PermissionService;
import com.jpro.module.system.service.user.AdminUserService;
import com.jprocms.module.cms.api.GlobalConfigApi;
import com.jprocms.module.cms.api.dto.GlobalConfigRespVO;
import com.jprocms.module.cms.api.dto.SecurityConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import static com.jpro.framework.common.pojo.CommonResult.success;
import static com.jpro.framework.common.util.collection.CollectionUtils.convertSet;
import static com.jpro.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.jprocms.module.cms.constant.CmsSysConstants.CMS_TENANT_ID;

@Slf4j
@RestController // 提供 RESTful API 接口，给 Feign 调用
@Validated
public class AdminUserApiImpl implements AdminUserApi {

    @Resource
    private AdminUserService userService;
    @Resource
    private DeptService deptService;
    @Resource
    private AdminAuthService authService;
    @Resource
    private JproProperties jproProperties;
    @Resource
    private AdminUserMapper adminUserMapper;
    @Resource
    private GlobalConfigApi globalConfigApi;
    @Resource
    private PermissionService permissionService;
    @Resource
    private MemberGroupService memberGroupService;

    @Override
    public CommonResult<AdminUserRespDTO> getUser(Long id) {
        AdminUserDO user = userService.getUser(id);
        return success(BeanUtils.toBean(user, AdminUserRespDTO.class));
    }

    @Override
    public CommonResult<List<AdminUserRespDTO>> getUserListBySubordinate(Long id) {
        // 1.1 获取用户负责的部门
        AdminUserDO user = userService.getUser(id);
        if (user == null) {
            return success(Collections.emptyList());
        }
        ArrayList<Long> deptIds = new ArrayList<>();
        DeptDO dept = deptService.getDept(user.getDeptId());
        if (dept == null) {
            return success(Collections.emptyList());
        }
        if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人
            return success(Collections.emptyList());
        }
        deptIds.add(dept.getId());
        // 1.2 获取所有子部门
        List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
        if (CollUtil.isNotEmpty(childDeptList)) {
            deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
        }

        // 2. 获取部门对应的用户信息
        List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
        users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
        return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
    }

    @Override
    public CommonResult<List<AdminUserRespDTO>> getUserList(Collection<Long> ids) {
        List<AdminUserDO> users = userService.getUserList(ids);
        return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
    }

    @Override
    public CommonResult<List<AdminUserRespDTO>> getUserListByDeptIds(Collection<Long> deptIds) {
        List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
        return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
    }

    @Override
    public CommonResult<List<AdminUserRespDTO>> getUserListByPostIds(Collection<Long> postIds) {
        List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
        return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
    }

    @Override
    public CommonResult<Boolean> validateUserList(Collection<Long> ids) {
        userService.validateUserList(ids);
        return success(true);
    }

    @Override
    public CommonResult<MemberUserRespDTO> getMember(Long id) {
        AdminUserDO user = userService.getUser(id);
        MemberUserRespDTO memberUserRespDTO = UserConvert.INSTANCE.convertForMember(user);
        if(user.getDeptId()!=null){
            memberUserRespDTO.setDeptName(deptService.getDept(user.getDeptId()).getName());
        }
        return success(memberUserRespDTO);
    }

    @Override
    public CommonResult<Long> registerMember(MemberCreateReqDTO reqDTO) {
        final Long memberId = userService.createMember(reqDTO, reqDTO.getStatus());
        //注册用户自动赋予系统分组
        final MemberGroupExportReqVO reqVO = new MemberGroupExportReqVO();
        reqVO.setType(EnumMemberGroupType.SYSTEM.getType());
        final List<MemberGroupDO> memberGroupList = memberGroupService.getMemberGroupList(reqVO);
        permissionService.assignUserGroup(memberId, CollectionUtils.convertSet(memberGroupList, MemberGroupDO::getId));
        return success(memberId);
    }

    @Override
    public CommonResult<Boolean> updateUserProfile(UserProfileUpdateReqVO reqVO) {
        userService.updateUserProfile(getLoginUserId(), reqVO);
        return success(true);
    }

    @Override
    public CommonResult<Boolean> updateUserProfilePassword(UserProfileUpdatePasswordReqVO reqVO) {
        userService.updateUserPassword(getLoginUserId(), reqVO);
        return success(true);
    }

    @Override
    public CommonResult<Boolean> resetUserPassword(MemberResetPasswordReqVO reqVO) {
        userService.resetUserPassword(reqVO.getId(), reqVO.getPassword());
        return success(true);
    }

    @Override
    public CommonResult<String> updateUserAvatar(MultipartFile file) throws Exception {
        return success(userService.updateUserAvatar(getLoginUserId(), file.getInputStream()));
    }

    @Override
    public CommonResult<String> updateUserAvatarUrl(UserAvatarDto avatarDto) {
        return success(userService.updateUserAvatar(getLoginUserId(), avatarDto.getUrl()));
    }

    @Override
    public CommonResult<MemberUserRespVo> cmslogin(SimpleAuthLoginReqVO reqVO) {
        return success(authService.simpleLogin(reqVO));
    }

    @Override
    public CommonResult<Boolean> logout(String token) {
        authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
        return success(true);
    }

    @Override
    public CommonResult<String> getClientPublicKey() {
        return success(jproProperties.getClientSm2PublicKey());
    }

    @Override
    public CommonResult<MemberAuthLoginRespVO> refreshToken(String refreshToken) {
        return success(authService.refreshTokenPortal(refreshToken));
    }

    @Override
    public CommonResult<AdminUserRespDTO> selectByEmail(String email) {
        return success(UserConvert.INSTANCE.convert4(userService.getUserByEmail(email)));
    }

    @Override
    public CommonResult<AdminUserRespDTO> selectByMobile(String mobile) {
        return success(UserConvert.INSTANCE.convert4(userService.getUserByMobile(mobile)));
    }

    @Override
    public CommonResult<AdminUserRespDTO> selectByUsername(String username) {
        return success(UserConvert.INSTANCE.convert4(userService.getUserByUsername(username)));
    }

    @Override
    public CommonResult<Boolean> checkLongTimeNoLoginUser() {
        TenantContextHolder.setTenantId(CMS_TENANT_ID);
        final CommonResult<GlobalConfigRespVO> globalConfigResp = globalConfigApi.getGlobalConfig();
        if (globalConfigResp.isSuccess()) {
            final SecurityConfig securityConfig = globalConfigResp.getData().getSecurityConfig();
            //未开启直接返回 或者多长时间(天)未登录锁定账号 小于等于0
            if (!securityConfig.isAdminIdleLock() || securityConfig.getAdminIdleDays() <= 0) {
                return success(true);
            }
            com.jpro.module.system.controller.admin.user.vo.user.UserPageReqVO reqVO = new com.jpro.module.system.controller.admin.user.vo.user.UserPageReqVO();
            reqVO.setPageNo(1);
            reqVO.setPageSize(100);
            doCheckNextPageUser(reqVO, securityConfig);
            return success(true);
        }
        return success(false);
    }

    private void doCheckNextPageUser(com.jpro.module.system.controller.admin.user.vo.user.UserPageReqVO reqVO, SecurityConfig securityConfig) {
        final PageResult<AdminUserDO> userDOPageResult = userService.getUserPage(reqVO);
        final List<AdminUserDO> list = userDOPageResult.getList();
        //执行检查逻辑和锁定
        doCheckLongTimeNoLoginUser(list, securityConfig);
        while (userDOPageResult.getHasNext()) {
            reqVO.setPageNo(userDOPageResult.getCurrent().intValue() + 1);
            doCheckNextPageUser(reqVO, securityConfig);
        }
    }

    private void doCheckLongTimeNoLoginUser(List<AdminUserDO> adminUserDOS, SecurityConfig securityConfig) {
        final LocalDateTime now = LocalDateTimeUtil.now();
        Date nowDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        for (AdminUserDO userDO : adminUserDOS) {
            //未登录过的账户则认为最后登录时间以创建时间为准
            Date lastLoginDate = Date.from(userDO.getCreateTime().atZone(ZoneId.systemDefault()).toInstant());
            if (userDO.getLoginDate() != null) {
                lastLoginDate = Date.from(userDO.getLoginDate().atZone(ZoneId.systemDefault()).toInstant());
            }
            final long lastLoginDays = DateUtil.betweenDay(lastLoginDate, nowDate, false);
            if (lastLoginDays >= securityConfig.getAdminIdleDays()) {
                //停用
                log.info("长期未登录锁定账号 ID:{}", userDO.getId());
                TenantContextHolder.setTenantId(CMS_TENANT_ID);
                lockUser(new UserLockReqVO(userDO.getId(), "长期未登录锁定账号"));
            }
        }
    }

    @Override
    public CommonResult<Boolean> lockUser(UserLockReqVO reqVO) {
        userService.lockUser(reqVO);
        return success(true);
    }
}
